// $Id$
/*
 *  Copyright (C) 2007 Noury Solutions
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 3 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 */

#if (!NET_CF)
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.Data.SQLite;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;

namespace Northwind.DomainModel.EnterpriseLibrary
{


    public class NorthwindDb:
        CriticalFinalizerObject,
        IDisposable
    {
        public NorthwindDb(NorthwindDatabaseType type)
        {
            _DatabaseType=type;

            string fileExt=null;
            string resName=null;
            DbConnectionStringBuilder conStrBuilder=null;
            string provStr=null;

            switch (type)
            {
            case NorthwindDatabaseType.Access:
                fileExt="mdb";
                resName="Northwind.Resources.Northwind.mdb";
                conStrBuilder=new OleDbConnectionStringBuilder();
                ((OleDbConnectionStringBuilder)conStrBuilder).Provider="Microsoft.Jet.OLEDB.4.0";
                ((OleDbConnectionStringBuilder)conStrBuilder).DataSource="{0}";
                ((OleDbConnectionStringBuilder)conStrBuilder).PersistSecurityInfo=false;
                conStrBuilder["Mode"]="ReadWrite";
                provStr="System.Data.OleDb";
                break;
            case NorthwindDatabaseType.SqlClient:
                fileExt="mdf";
                resName="Northwind.Resources.Northwind.mdf";
                conStrBuilder=new SqlConnectionStringBuilder();
                ((SqlConnectionStringBuilder)conStrBuilder).DataSource=@".\SQLEXPRESS";
                ((SqlConnectionStringBuilder)conStrBuilder).AttachDBFilename="{0}";
                ((SqlConnectionStringBuilder)conStrBuilder).Enlist=true;
                ((SqlConnectionStringBuilder)conStrBuilder).IntegratedSecurity=true;
                ((SqlConnectionStringBuilder)conStrBuilder).Pooling=false;
                provStr="System.Data.SqlClient";
                break;
            case NorthwindDatabaseType.SqlCompact:
                fileExt="sdf";
                resName="Northwind.Resources.Northwind.sdf";
                conStrBuilder=new DbConnectionStringBuilder();
                conStrBuilder["Data Source"]="{0}";
                provStr="System.Data.SqlServerCe";
                break;
            case NorthwindDatabaseType.SQLite:
                fileExt="db";
                resName="Northwind.Resources.Northwind.db";
                conStrBuilder=new SQLiteConnectionStringBuilder();
                ((SQLiteConnectionStringBuilder)conStrBuilder).DataSource="{0}";
                provStr="SQLite";
                break;
            }

            _TempFileCollection=new TempFileCollection(Environment.GetEnvironmentVariable("SystemRoot")+@"\Temp", false);
            _Filename=_TempFileCollection.AddExtension(fileExt, false);
            using (BinaryWriter bw=new BinaryWriter(File.Open(_Filename, FileMode.Create)))
            {
                Stream source=Assembly.GetAssembly(GetType()).GetManifestResourceStream(resName);
                byte[] buffer=new byte[0x10000];
                int bytes;
                try
                {
                    while ((bytes=source.Read(buffer, 0, buffer.Length))>0)
                        bw.Write(buffer, 0, bytes);
                } finally
                {
                    bw.Flush();
                }
            }

            switch (type)
            {
            case NorthwindDatabaseType.SqlClient:
                _Database=new SqlDatabase(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        conStrBuilder.ToString(),
                        _Filename
                    )
                );
                break;
            default:
                _Database=new GenericDatabase(
                    string.Format(
                        CultureInfo.InvariantCulture,
                        conStrBuilder.ToString(),
                        _Filename
                    ),
                    DbProviderFactories.GetFactory(provStr)
                );
                break;
            }
        }

        ~NorthwindDb()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
#if (!NET_CF)
            // Clear the pool so that we can delete the .mdf file
            SqlDatabase sqlDb=_Database as SqlDatabase;
            if (sqlDb!=null)
                try
                {
                    System.Data.SqlClient.SqlConnection.ClearAllPools();
                    new SqlDatabase(@"Data Source=.\SQLEXPRESS;Database=master;Integrated Security=True")
                        .ExecuteNonQuery("sp_detach_db", _Filename, "true", "false");
                } catch
                {
                }
#endif

            if (_TempFileCollection!=null)
                _TempFileCollection.Delete();
        }

        public Database Database
        {
            get
            {
                return _Database;
            }
        }

        public NorthwindDatabaseType DatabaseType
        {
            get
            {
                return _DatabaseType;
            }
        }

        private TempFileCollection _TempFileCollection;
        private string _Filename;
        private Database _Database;
        private NorthwindDatabaseType _DatabaseType;
    }

    internal static class Utils
    {
        public static int GetLastId(Database database, IList<DbCommand> commands)
        {
            string selectId=Resources.Sql.SqlServerSelectId;

            Type factoryType=database.DbProviderFactory.GetType();
            if (factoryType==typeof(SQLiteFactory))
                selectId=Resources.Sql.SQLiteSelectId;

            DbCommand c=database.GetSqlStringCommand(selectId);
            c.Transaction=commands[0].Transaction;

            if (c.Transaction!=null)
                return Convert.ToInt32(database.ExecuteScalar(c, c.Transaction));
            else
                return Convert.ToInt32(database.ExecuteScalar(c));
        }
    }

}
#endif
